﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.ComponentModel;

namespace TR0217.ControlEx
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(PictureBox))]
    public class PictureBoxEx : Control
    {
        Cursor _curMove;
        public PictureBoxEx()
        {
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.Selectable, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            _curMove = new Cursor(this.GetType(), "hand.cur");
        }

        private Image _image;

        public Image Image
        {
            get { return _image; }
            set 
            {
                _image = value;
                if (_image != null)
                {
                    CalcShowRatio();
                    base.Invalidate();
                }
            }
        }

        BorderStyle _borderStyle = BorderStyle.None;
        public System.Windows.Forms.BorderStyle BorderStyle
        {
            get { return _borderStyle; }
            set { _borderStyle = value; }
        }

        Color _borderColor = Color.Black;
        public System.Drawing.Color BorderColor
        {
            get { return _borderColor; }
            set { _borderColor = value; }
        }

        double _initShowRatio = 1.0;
        double _showRatio = 1.0;
        double _minRatio = 1.0;
        Point _move = new Point(0,0);
        Rectangle _imgRect;

        void CalcShowRect()
        {
            Size logDestSize = Size.Empty;
            Point logDestPos = Point.Empty;

            logDestSize.Width = (int)((double)_image.Width * _showRatio);
            logDestSize.Height = (int)((double)_image.Height * _showRatio);

            logDestPos.X = (this.Width - logDestSize.Width) / 2 + _move.X;
            logDestPos.Y = (this.Height - logDestSize.Height) / 2 + _move.Y;
            _imgRect = new Rectangle(logDestPos.X, logDestPos.Y, logDestSize.Width, logDestSize.Height);
        }

        void CalcShowRatio()
        {
            Rectangle rect = new Rectangle(this.Padding.Left,
                this.Padding.Top,
                this.Width - this.Padding.Left - this.Padding.Right,
                this.Height - this.Padding.Top - this.Padding.Bottom);
            double wRatio = (double)rect.Width / (double)_image.Width;
            double hRatio = (double)rect.Height / (double)_image.Height;
            _showRatio = wRatio < hRatio ? wRatio : hRatio;
            _initShowRatio = _showRatio;
            _minRatio = _showRatio > 0.1 ? 0.1 : _showRatio;
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            if(_image != null) CalcShowRatio();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (this.Image != null)
            {
                this.CalcShowRect();
                e.Graphics.DrawImage(this.Image, _imgRect, 0, 0, this.Image.Width, this.Image.Height, GraphicsUnit.Pixel);
            }

            if (this.BorderStyle == BorderStyle.Fixed3D)
            {
                ControlPaint.DrawBorder3D(e.Graphics, 0, 0, this.Width, this.Height, Border3DStyle.Sunken);
            }
            else if (this.BorderStyle == BorderStyle.FixedSingle)
            {
                Pen p = new Pen(_borderColor);
                e.Graphics.DrawRectangle(p, 0, 0, this.Width-1, this.Height-1);
                p.Dispose();
            }
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            if (this.Image != null)
            {
                _showRatio -= (double)e.Delta / 1200.0;
                _showRatio = _showRatio < _minRatio ? _minRatio : _showRatio;
                this.Invalidate();
            }
        }

        bool _moving = false;
        public bool Moving
        {
            get { return _moving; }
            set 
            { 
                _moving = value;
                if (_moving)
                    this.Cursor = _curMove;
                else
                    this.Cursor = Cursors.Default;
            }
        }

        Point _mouseDownPos;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.Focus();
            if (e.Button == MouseButtons.Left)
            {
                if (_image != null && _imgRect.Contains(e.Location))
                {
                    Moving = true;
                    _mouseDownPos = e.Location;
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (_moving && this.ClientRectangle.Contains(e.Location))
            {
                _move = new Point(_move.X + e.Location.X - _mouseDownPos.X, _move.Y + e.Location.Y - _mouseDownPos.Y);
                _mouseDownPos = e.Location;
                this.Invalidate();
            }
            else
            {
                Moving = false;
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (_moving)
            {
                _move = new Point(_move.X + e.Location.X - _mouseDownPos.X, _move.Y + e.Location.Y - _mouseDownPos.Y);
                Moving = false;
                this.Invalidate();
            }
        }

        public void ResetMove()
        {
            Moving = false;
            _move = new Point(0, 0);
            this.Invalidate();
        }

        public void ResetZoom()
        {
            _showRatio = _initShowRatio;
            this.Invalidate();
        }
    }
}
